{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "from torch_geometric.datasets import Planetoid\n",
    "import torch_geometric.transforms as T\n",
    "from torch_geometric.nn import GCNConv\n",
    "from torch_geometric.utils import train_test_split_edges"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tutorial 6  \n",
    "Graph AutoEncoders GAE &  \n",
    "Variational Graph Autoencoders VGAE    \n",
    "\n",
    "[paper](https://arxiv.org/pdf/1611.07308.pdf)  \n",
    "[code](https://github.com/rusty1s/pytorch_geometric/blob/master/examples/autoencoder.py)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Graph AutoEncoder GAE"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load the data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Data(edge_index=[2, 9104], test_mask=[3327], train_mask=[3327], val_mask=[3327], x=[3327, 3703], y=[3327])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dataset = Planetoid(\"\\..\", \"CiteSeer\", transform=T.NormalizeFeatures())\n",
    "dataset.data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Data(edge_index=[2, 9104], x=[3327, 3703], y=[3327])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = dataset[0]\n",
    "data.train_mask = data.val_mask = data.test_mask = None\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = train_test_split_edges(data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Data(test_neg_edge_index=[2, 455], test_pos_edge_index=[2, 455], train_neg_adj_mask=[3327, 3327], train_pos_edge_index=[2, 7740], val_neg_edge_index=[2, 227], val_pos_edge_index=[2, 227], x=[3327, 3703], y=[3327])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define the Encoder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class GCNEncoder(torch.nn.Module):\n",
    "    def __init__(self, in_channels, out_channels):\n",
    "        super(GCNEncoder, self).__init__()\n",
    "        self.conv1 = GCNConv(in_channels, 2 * out_channels, cached=True) # cached only for transductive learning\n",
    "        self.conv2 = GCNConv(2 * out_channels, out_channels, cached=True) # cached only for transductive learning\n",
    "\n",
    "    def forward(self, x, edge_index):\n",
    "        x = self.conv1(x, edge_index).relu()\n",
    "        return self.conv2(x, edge_index)\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define the Autoencoder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch_geometric.nn import GAE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# parameters\n",
    "out_channels = 2\n",
    "num_features = dataset.num_features\n",
    "epochs = 100\n",
    "\n",
    "# model\n",
    "model = GAE(GCNEncoder(num_features, out_channels))\n",
    "\n",
    "# move to GPU (if available)\n",
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "model = model.to(device)\n",
    "x = data.x.to(device)\n",
    "train_pos_edge_index = data.train_pos_edge_index.to(device)\n",
    "\n",
    "# inizialize the optimizer\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.01)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train():\n",
    "    model.train()\n",
    "    optimizer.zero_grad()\n",
    "    z = model.encode(x, train_pos_edge_index)\n",
    "    loss = model.recon_loss(z, train_pos_edge_index)\n",
    "    #if args.variational:\n",
    "    #   loss = loss + (1 / data.num_nodes) * model.kl_loss()\n",
    "    loss.backward()\n",
    "    optimizer.step()\n",
    "    return float(loss)\n",
    "\n",
    "\n",
    "def test(pos_edge_index, neg_edge_index):\n",
    "    model.eval()\n",
    "    with torch.no_grad():\n",
    "        z = model.encode(x, train_pos_edge_index)\n",
    "    return model.test(z, pos_edge_index, neg_edge_index)\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 001, AUC: 0.6145, AP: 0.6514\n",
      "Epoch: 002, AUC: 0.6269, AP: 0.6642\n",
      "Epoch: 003, AUC: 0.6315, AP: 0.6691\n",
      "Epoch: 004, AUC: 0.6334, AP: 0.6713\n",
      "Epoch: 005, AUC: 0.6346, AP: 0.6726\n",
      "Epoch: 006, AUC: 0.6351, AP: 0.6741\n",
      "Epoch: 007, AUC: 0.6359, AP: 0.6752\n",
      "Epoch: 008, AUC: 0.6365, AP: 0.6764\n",
      "Epoch: 009, AUC: 0.6372, AP: 0.6779\n",
      "Epoch: 010, AUC: 0.6379, AP: 0.6802\n",
      "Epoch: 011, AUC: 0.6389, AP: 0.6824\n",
      "Epoch: 012, AUC: 0.6399, AP: 0.6850\n",
      "Epoch: 013, AUC: 0.6406, AP: 0.6876\n",
      "Epoch: 014, AUC: 0.6416, AP: 0.6907\n",
      "Epoch: 015, AUC: 0.6421, AP: 0.6941\n",
      "Epoch: 016, AUC: 0.6426, AP: 0.6973\n",
      "Epoch: 017, AUC: 0.6430, AP: 0.7002\n",
      "Epoch: 018, AUC: 0.6432, AP: 0.7035\n",
      "Epoch: 019, AUC: 0.6434, AP: 0.7059\n",
      "Epoch: 020, AUC: 0.6431, AP: 0.7074\n",
      "Epoch: 021, AUC: 0.6431, AP: 0.7091\n",
      "Epoch: 022, AUC: 0.6433, AP: 0.7105\n",
      "Epoch: 023, AUC: 0.6435, AP: 0.7114\n",
      "Epoch: 024, AUC: 0.6437, AP: 0.7121\n",
      "Epoch: 025, AUC: 0.6441, AP: 0.7128\n",
      "Epoch: 026, AUC: 0.6446, AP: 0.7142\n",
      "Epoch: 027, AUC: 0.6448, AP: 0.7147\n",
      "Epoch: 028, AUC: 0.6456, AP: 0.7160\n",
      "Epoch: 029, AUC: 0.6465, AP: 0.7171\n",
      "Epoch: 030, AUC: 0.6482, AP: 0.7187\n",
      "Epoch: 031, AUC: 0.6503, AP: 0.7201\n",
      "Epoch: 032, AUC: 0.6535, AP: 0.7223\n",
      "Epoch: 033, AUC: 0.6577, AP: 0.7244\n",
      "Epoch: 034, AUC: 0.6625, AP: 0.7268\n",
      "Epoch: 035, AUC: 0.6681, AP: 0.7292\n",
      "Epoch: 036, AUC: 0.6749, AP: 0.7322\n",
      "Epoch: 037, AUC: 0.6805, AP: 0.7346\n",
      "Epoch: 038, AUC: 0.6842, AP: 0.7361\n",
      "Epoch: 039, AUC: 0.6883, AP: 0.7379\n",
      "Epoch: 040, AUC: 0.6936, AP: 0.7402\n",
      "Epoch: 041, AUC: 0.7003, AP: 0.7431\n",
      "Epoch: 042, AUC: 0.7086, AP: 0.7468\n",
      "Epoch: 043, AUC: 0.7203, AP: 0.7523\n",
      "Epoch: 044, AUC: 0.7298, AP: 0.7573\n",
      "Epoch: 045, AUC: 0.7380, AP: 0.7620\n",
      "Epoch: 046, AUC: 0.7442, AP: 0.7656\n",
      "Epoch: 047, AUC: 0.7498, AP: 0.7687\n",
      "Epoch: 048, AUC: 0.7528, AP: 0.7706\n",
      "Epoch: 049, AUC: 0.7555, AP: 0.7723\n",
      "Epoch: 050, AUC: 0.7583, AP: 0.7741\n",
      "Epoch: 051, AUC: 0.7608, AP: 0.7755\n",
      "Epoch: 052, AUC: 0.7641, AP: 0.7773\n",
      "Epoch: 053, AUC: 0.7664, AP: 0.7788\n",
      "Epoch: 054, AUC: 0.7679, AP: 0.7798\n",
      "Epoch: 055, AUC: 0.7689, AP: 0.7803\n",
      "Epoch: 056, AUC: 0.7691, AP: 0.7798\n",
      "Epoch: 057, AUC: 0.7691, AP: 0.7796\n",
      "Epoch: 058, AUC: 0.7691, AP: 0.7796\n",
      "Epoch: 059, AUC: 0.7700, AP: 0.7803\n",
      "Epoch: 060, AUC: 0.7708, AP: 0.7811\n",
      "Epoch: 061, AUC: 0.7714, AP: 0.7815\n",
      "Epoch: 062, AUC: 0.7724, AP: 0.7822\n",
      "Epoch: 063, AUC: 0.7730, AP: 0.7823\n",
      "Epoch: 064, AUC: 0.7736, AP: 0.7826\n",
      "Epoch: 065, AUC: 0.7742, AP: 0.7828\n",
      "Epoch: 066, AUC: 0.7756, AP: 0.7832\n",
      "Epoch: 067, AUC: 0.7763, AP: 0.7833\n",
      "Epoch: 068, AUC: 0.7764, AP: 0.7830\n",
      "Epoch: 069, AUC: 0.7765, AP: 0.7820\n",
      "Epoch: 070, AUC: 0.7770, AP: 0.7826\n",
      "Epoch: 071, AUC: 0.7772, AP: 0.7828\n",
      "Epoch: 072, AUC: 0.7762, AP: 0.7816\n",
      "Epoch: 073, AUC: 0.7762, AP: 0.7815\n",
      "Epoch: 074, AUC: 0.7756, AP: 0.7805\n",
      "Epoch: 075, AUC: 0.7744, AP: 0.7788\n",
      "Epoch: 076, AUC: 0.7742, AP: 0.7784\n",
      "Epoch: 077, AUC: 0.7736, AP: 0.7777\n",
      "Epoch: 078, AUC: 0.7729, AP: 0.7767\n",
      "Epoch: 079, AUC: 0.7733, AP: 0.7771\n",
      "Epoch: 080, AUC: 0.7736, AP: 0.7777\n",
      "Epoch: 081, AUC: 0.7735, AP: 0.7781\n",
      "Epoch: 082, AUC: 0.7736, AP: 0.7783\n",
      "Epoch: 083, AUC: 0.7737, AP: 0.7785\n",
      "Epoch: 084, AUC: 0.7730, AP: 0.7775\n",
      "Epoch: 085, AUC: 0.7727, AP: 0.7769\n",
      "Epoch: 086, AUC: 0.7725, AP: 0.7771\n",
      "Epoch: 087, AUC: 0.7724, AP: 0.7773\n",
      "Epoch: 088, AUC: 0.7722, AP: 0.7770\n",
      "Epoch: 089, AUC: 0.7722, AP: 0.7772\n",
      "Epoch: 090, AUC: 0.7723, AP: 0.7774\n",
      "Epoch: 091, AUC: 0.7716, AP: 0.7765\n",
      "Epoch: 092, AUC: 0.7710, AP: 0.7758\n",
      "Epoch: 093, AUC: 0.7712, AP: 0.7764\n",
      "Epoch: 094, AUC: 0.7712, AP: 0.7765\n",
      "Epoch: 095, AUC: 0.7705, AP: 0.7754\n",
      "Epoch: 096, AUC: 0.7702, AP: 0.7752\n",
      "Epoch: 097, AUC: 0.7695, AP: 0.7744\n",
      "Epoch: 098, AUC: 0.7707, AP: 0.7760\n",
      "Epoch: 099, AUC: 0.7702, AP: 0.7752\n",
      "Epoch: 100, AUC: 0.7698, AP: 0.7742\n"
     ]
    }
   ],
   "source": [
    "for epoch in range(1, epochs + 1):\n",
    "    loss = train()\n",
    "\n",
    "    auc, ap = test(data.test_pos_edge_index, data.test_neg_edge_index)\n",
    "    print('Epoch: {:03d}, AUC: {:.4f}, AP: {:.4f}'.format(epoch, auc, ap))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0.4781, -0.6356],\n",
       "        [-0.9415,  1.1525],\n",
       "        [ 0.5803, -0.7327],\n",
       "        ...,\n",
       "        [-0.3368,  0.3879],\n",
       "        [ 0.5803, -0.7327],\n",
       "        [ 0.5803, -0.7327]], device='cuda:0', grad_fn=<AddBackward0>)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Z = model.encode(x, train_pos_edge_index)\n",
    "Z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Are the results (AUC) and (AP) easy to read and compare?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Use Tensorboard"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch.utils.tensorboard import SummaryWriter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# parameters\n",
    "out_channels = 2\n",
    "num_features = dataset.num_features\n",
    "epochs = 100\n",
    "\n",
    "# model\n",
    "model = GAE(GCNEncoder(num_features, out_channels))\n",
    "\n",
    "# move to GPU (if available)\n",
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "model = model.to(device)\n",
    "x = data.x.to(device)\n",
    "train_pos_edge_index = data.train_pos_edge_index.to(device)\n",
    "\n",
    "# inizialize the optimizer\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.01)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Import tensorboard\n",
    "\n",
    "#### Installation: (if needed) \"pip install tensorboard\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "writer = SummaryWriter('runs/GAE1_experiment_'+'2d_100_epochs')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 001, AUC: 0.5902, AP: 0.6221\n",
      "Epoch: 002, AUC: 0.6100, AP: 0.6425\n",
      "Epoch: 003, AUC: 0.6175, AP: 0.6520\n",
      "Epoch: 004, AUC: 0.6227, AP: 0.6574\n",
      "Epoch: 005, AUC: 0.6269, AP: 0.6621\n",
      "Epoch: 006, AUC: 0.6294, AP: 0.6647\n",
      "Epoch: 007, AUC: 0.6310, AP: 0.6672\n",
      "Epoch: 008, AUC: 0.6326, AP: 0.6700\n",
      "Epoch: 009, AUC: 0.6342, AP: 0.6729\n",
      "Epoch: 010, AUC: 0.6359, AP: 0.6770\n",
      "Epoch: 011, AUC: 0.6372, AP: 0.6806\n",
      "Epoch: 012, AUC: 0.6389, AP: 0.6853\n",
      "Epoch: 013, AUC: 0.6401, AP: 0.6896\n",
      "Epoch: 014, AUC: 0.6415, AP: 0.6938\n",
      "Epoch: 015, AUC: 0.6420, AP: 0.6975\n",
      "Epoch: 016, AUC: 0.6420, AP: 0.7015\n",
      "Epoch: 017, AUC: 0.6427, AP: 0.7048\n",
      "Epoch: 018, AUC: 0.6425, AP: 0.7065\n",
      "Epoch: 019, AUC: 0.6425, AP: 0.7080\n",
      "Epoch: 020, AUC: 0.6432, AP: 0.7096\n",
      "Epoch: 021, AUC: 0.6434, AP: 0.7109\n",
      "Epoch: 022, AUC: 0.6439, AP: 0.7118\n",
      "Epoch: 023, AUC: 0.6443, AP: 0.7128\n",
      "Epoch: 024, AUC: 0.6452, AP: 0.7139\n",
      "Epoch: 025, AUC: 0.6459, AP: 0.7150\n",
      "Epoch: 026, AUC: 0.6469, AP: 0.7162\n",
      "Epoch: 027, AUC: 0.6485, AP: 0.7180\n",
      "Epoch: 028, AUC: 0.6504, AP: 0.7199\n",
      "Epoch: 029, AUC: 0.6534, AP: 0.7218\n",
      "Epoch: 030, AUC: 0.6574, AP: 0.7238\n",
      "Epoch: 031, AUC: 0.6627, AP: 0.7265\n",
      "Epoch: 032, AUC: 0.6684, AP: 0.7291\n",
      "Epoch: 033, AUC: 0.6741, AP: 0.7317\n",
      "Epoch: 034, AUC: 0.6786, AP: 0.7337\n",
      "Epoch: 035, AUC: 0.6833, AP: 0.7357\n",
      "Epoch: 036, AUC: 0.6874, AP: 0.7374\n",
      "Epoch: 037, AUC: 0.6925, AP: 0.7396\n",
      "Epoch: 038, AUC: 0.7011, AP: 0.7435\n",
      "Epoch: 039, AUC: 0.7114, AP: 0.7480\n",
      "Epoch: 040, AUC: 0.7203, AP: 0.7526\n",
      "Epoch: 041, AUC: 0.7307, AP: 0.7583\n",
      "Epoch: 042, AUC: 0.7379, AP: 0.7622\n",
      "Epoch: 043, AUC: 0.7435, AP: 0.7657\n",
      "Epoch: 044, AUC: 0.7474, AP: 0.7679\n",
      "Epoch: 045, AUC: 0.7495, AP: 0.7691\n",
      "Epoch: 046, AUC: 0.7528, AP: 0.7711\n",
      "Epoch: 047, AUC: 0.7575, AP: 0.7739\n",
      "Epoch: 048, AUC: 0.7610, AP: 0.7762\n",
      "Epoch: 049, AUC: 0.7650, AP: 0.7786\n",
      "Epoch: 050, AUC: 0.7686, AP: 0.7805\n",
      "Epoch: 051, AUC: 0.7683, AP: 0.7795\n",
      "Epoch: 052, AUC: 0.7689, AP: 0.7799\n",
      "Epoch: 053, AUC: 0.7687, AP: 0.7798\n",
      "Epoch: 054, AUC: 0.7687, AP: 0.7798\n",
      "Epoch: 055, AUC: 0.7689, AP: 0.7800\n",
      "Epoch: 056, AUC: 0.7693, AP: 0.7799\n",
      "Epoch: 057, AUC: 0.7711, AP: 0.7810\n",
      "Epoch: 058, AUC: 0.7728, AP: 0.7821\n",
      "Epoch: 059, AUC: 0.7734, AP: 0.7819\n",
      "Epoch: 060, AUC: 0.7736, AP: 0.7819\n",
      "Epoch: 061, AUC: 0.7739, AP: 0.7818\n",
      "Epoch: 062, AUC: 0.7744, AP: 0.7816\n",
      "Epoch: 063, AUC: 0.7757, AP: 0.7827\n",
      "Epoch: 064, AUC: 0.7757, AP: 0.7817\n",
      "Epoch: 065, AUC: 0.7762, AP: 0.7815\n",
      "Epoch: 066, AUC: 0.7760, AP: 0.7812\n",
      "Epoch: 067, AUC: 0.7766, AP: 0.7812\n",
      "Epoch: 068, AUC: 0.7765, AP: 0.7811\n",
      "Epoch: 069, AUC: 0.7762, AP: 0.7807\n",
      "Epoch: 070, AUC: 0.7762, AP: 0.7806\n",
      "Epoch: 071, AUC: 0.7757, AP: 0.7794\n",
      "Epoch: 072, AUC: 0.7758, AP: 0.7795\n",
      "Epoch: 073, AUC: 0.7758, AP: 0.7795\n",
      "Epoch: 074, AUC: 0.7753, AP: 0.7789\n",
      "Epoch: 075, AUC: 0.7753, AP: 0.7793\n",
      "Epoch: 076, AUC: 0.7746, AP: 0.7786\n",
      "Epoch: 077, AUC: 0.7743, AP: 0.7783\n",
      "Epoch: 078, AUC: 0.7741, AP: 0.7783\n",
      "Epoch: 079, AUC: 0.7741, AP: 0.7787\n",
      "Epoch: 080, AUC: 0.7741, AP: 0.7787\n",
      "Epoch: 081, AUC: 0.7739, AP: 0.7783\n",
      "Epoch: 082, AUC: 0.7729, AP: 0.7774\n",
      "Epoch: 083, AUC: 0.7726, AP: 0.7773\n",
      "Epoch: 084, AUC: 0.7725, AP: 0.7775\n",
      "Epoch: 085, AUC: 0.7724, AP: 0.7774\n",
      "Epoch: 086, AUC: 0.7722, AP: 0.7772\n",
      "Epoch: 087, AUC: 0.7718, AP: 0.7766\n",
      "Epoch: 088, AUC: 0.7717, AP: 0.7765\n",
      "Epoch: 089, AUC: 0.7714, AP: 0.7765\n",
      "Epoch: 090, AUC: 0.7712, AP: 0.7765\n",
      "Epoch: 091, AUC: 0.7712, AP: 0.7768\n",
      "Epoch: 092, AUC: 0.7714, AP: 0.7773\n",
      "Epoch: 093, AUC: 0.7711, AP: 0.7768\n",
      "Epoch: 094, AUC: 0.7706, AP: 0.7759\n",
      "Epoch: 095, AUC: 0.7708, AP: 0.7753\n",
      "Epoch: 096, AUC: 0.7712, AP: 0.7754\n",
      "Epoch: 097, AUC: 0.7710, AP: 0.7754\n",
      "Epoch: 098, AUC: 0.7705, AP: 0.7757\n",
      "Epoch: 099, AUC: 0.7707, AP: 0.7760\n",
      "Epoch: 100, AUC: 0.7707, AP: 0.7760\n"
     ]
    }
   ],
   "source": [
    "for epoch in range(1, epochs + 1):\n",
    "    loss = train()\n",
    "    auc, ap = test(data.test_pos_edge_index, data.test_neg_edge_index)\n",
    "    print('Epoch: {:03d}, AUC: {:.4f}, AP: {:.4f}'.format(epoch, auc, ap))\n",
    "    \n",
    "    \n",
    "    writer.add_scalar('auc train',auc,epoch) # new line\n",
    "    writer.add_scalar('ap train',ap,epoch)   # new line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Graph Variational AutoEncoder (GVAE)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch_geometric.nn import VGAE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "dataset = Planetoid(\"\\..\", \"CiteSeer\", transform=T.NormalizeFeatures())\n",
    "data = dataset[0]\n",
    "data.train_mask = data.val_mask = data.test_mask = data.y = None\n",
    "data = train_test_split_edges(data)\n",
    "\n",
    "\n",
    "class VariationalGCNEncoder(torch.nn.Module):\n",
    "    def __init__(self, in_channels, out_channels):\n",
    "        super(VariationalGCNEncoder, self).__init__()\n",
    "        self.conv1 = GCNConv(in_channels, 2 * out_channels, cached=True) # cached only for transductive learning\n",
    "        self.conv_mu = GCNConv(2 * out_channels, out_channels, cached=True)\n",
    "        self.conv_logstd = GCNConv(2 * out_channels, out_channels, cached=True)\n",
    "\n",
    "    def forward(self, x, edge_index):\n",
    "        x = self.conv1(x, edge_index).relu()\n",
    "        return self.conv_mu(x, edge_index), self.conv_logstd(x, edge_index)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "out_channels = 2\n",
    "num_features = dataset.num_features\n",
    "epochs = 300\n",
    "\n",
    "\n",
    "model = VGAE(VariationalGCNEncoder(num_features, out_channels))  # new line\n",
    "\n",
    "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
    "model = model.to(device)\n",
    "x = data.x.to(device)\n",
    "train_pos_edge_index = data.train_pos_edge_index.to(device)\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.01)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train():\n",
    "    model.train()\n",
    "    optimizer.zero_grad()\n",
    "    z = model.encode(x, train_pos_edge_index)\n",
    "    loss = model.recon_loss(z, train_pos_edge_index)\n",
    "    \n",
    "    loss = loss + (1 / data.num_nodes) * model.kl_loss()  # new line\n",
    "    loss.backward()\n",
    "    optimizer.step()\n",
    "    return float(loss)\n",
    "\n",
    "\n",
    "def test(pos_edge_index, neg_edge_index):\n",
    "    model.eval()\n",
    "    with torch.no_grad():\n",
    "        z = model.encode(x, train_pos_edge_index)\n",
    "    return model.test(z, pos_edge_index, neg_edge_index)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 001, AUC: 0.6165, AP: 0.6573\n",
      "Epoch: 002, AUC: 0.6305, AP: 0.6628\n",
      "Epoch: 003, AUC: 0.6340, AP: 0.6635\n",
      "Epoch: 004, AUC: 0.6355, AP: 0.6642\n",
      "Epoch: 005, AUC: 0.6364, AP: 0.6645\n",
      "Epoch: 006, AUC: 0.6373, AP: 0.6656\n",
      "Epoch: 007, AUC: 0.6374, AP: 0.6662\n",
      "Epoch: 008, AUC: 0.6374, AP: 0.6664\n",
      "Epoch: 009, AUC: 0.6375, AP: 0.6669\n",
      "Epoch: 010, AUC: 0.6377, AP: 0.6674\n",
      "Epoch: 011, AUC: 0.6379, AP: 0.6677\n",
      "Epoch: 012, AUC: 0.6380, AP: 0.6679\n",
      "Epoch: 013, AUC: 0.6380, AP: 0.6683\n",
      "Epoch: 014, AUC: 0.6382, AP: 0.6687\n",
      "Epoch: 015, AUC: 0.6385, AP: 0.6690\n",
      "Epoch: 016, AUC: 0.6386, AP: 0.6694\n",
      "Epoch: 017, AUC: 0.6388, AP: 0.6700\n",
      "Epoch: 018, AUC: 0.6391, AP: 0.6705\n",
      "Epoch: 019, AUC: 0.6392, AP: 0.6709\n",
      "Epoch: 020, AUC: 0.6394, AP: 0.6713\n",
      "Epoch: 021, AUC: 0.6394, AP: 0.6715\n",
      "Epoch: 022, AUC: 0.6395, AP: 0.6718\n",
      "Epoch: 023, AUC: 0.6394, AP: 0.6721\n",
      "Epoch: 024, AUC: 0.6392, AP: 0.6723\n",
      "Epoch: 025, AUC: 0.6391, AP: 0.6724\n",
      "Epoch: 026, AUC: 0.6391, AP: 0.6727\n",
      "Epoch: 027, AUC: 0.6391, AP: 0.6729\n",
      "Epoch: 028, AUC: 0.6389, AP: 0.6729\n",
      "Epoch: 029, AUC: 0.6389, AP: 0.6732\n",
      "Epoch: 030, AUC: 0.6388, AP: 0.6735\n",
      "Epoch: 031, AUC: 0.6389, AP: 0.6738\n",
      "Epoch: 032, AUC: 0.6390, AP: 0.6741\n",
      "Epoch: 033, AUC: 0.6391, AP: 0.6745\n",
      "Epoch: 034, AUC: 0.6392, AP: 0.6748\n",
      "Epoch: 035, AUC: 0.6394, AP: 0.6753\n",
      "Epoch: 036, AUC: 0.6398, AP: 0.6759\n",
      "Epoch: 037, AUC: 0.6402, AP: 0.6765\n",
      "Epoch: 038, AUC: 0.6405, AP: 0.6770\n",
      "Epoch: 039, AUC: 0.6409, AP: 0.6777\n",
      "Epoch: 040, AUC: 0.6414, AP: 0.6785\n",
      "Epoch: 041, AUC: 0.6418, AP: 0.6792\n",
      "Epoch: 042, AUC: 0.6422, AP: 0.6800\n",
      "Epoch: 043, AUC: 0.6426, AP: 0.6808\n",
      "Epoch: 044, AUC: 0.6430, AP: 0.6816\n",
      "Epoch: 045, AUC: 0.6435, AP: 0.6823\n",
      "Epoch: 046, AUC: 0.6438, AP: 0.6830\n",
      "Epoch: 047, AUC: 0.6441, AP: 0.6837\n",
      "Epoch: 048, AUC: 0.6445, AP: 0.6845\n",
      "Epoch: 049, AUC: 0.6449, AP: 0.6855\n",
      "Epoch: 050, AUC: 0.6453, AP: 0.6865\n",
      "Epoch: 051, AUC: 0.6454, AP: 0.6871\n",
      "Epoch: 052, AUC: 0.6454, AP: 0.6879\n",
      "Epoch: 053, AUC: 0.6458, AP: 0.6890\n",
      "Epoch: 054, AUC: 0.6457, AP: 0.6897\n",
      "Epoch: 055, AUC: 0.6456, AP: 0.6905\n",
      "Epoch: 056, AUC: 0.6458, AP: 0.6911\n",
      "Epoch: 057, AUC: 0.6460, AP: 0.6921\n",
      "Epoch: 058, AUC: 0.6462, AP: 0.6928\n",
      "Epoch: 059, AUC: 0.6463, AP: 0.6936\n",
      "Epoch: 060, AUC: 0.6464, AP: 0.6941\n",
      "Epoch: 061, AUC: 0.6464, AP: 0.6947\n",
      "Epoch: 062, AUC: 0.6467, AP: 0.6956\n",
      "Epoch: 063, AUC: 0.6469, AP: 0.6964\n",
      "Epoch: 064, AUC: 0.6470, AP: 0.6970\n",
      "Epoch: 065, AUC: 0.6471, AP: 0.6978\n",
      "Epoch: 066, AUC: 0.6474, AP: 0.6986\n",
      "Epoch: 067, AUC: 0.6476, AP: 0.6995\n",
      "Epoch: 068, AUC: 0.6476, AP: 0.7001\n",
      "Epoch: 069, AUC: 0.6479, AP: 0.7011\n",
      "Epoch: 070, AUC: 0.6481, AP: 0.7020\n",
      "Epoch: 071, AUC: 0.6484, AP: 0.7028\n",
      "Epoch: 072, AUC: 0.6489, AP: 0.7038\n",
      "Epoch: 073, AUC: 0.6494, AP: 0.7048\n",
      "Epoch: 074, AUC: 0.6497, AP: 0.7055\n",
      "Epoch: 075, AUC: 0.6500, AP: 0.7065\n",
      "Epoch: 076, AUC: 0.6501, AP: 0.7071\n",
      "Epoch: 077, AUC: 0.6507, AP: 0.7079\n",
      "Epoch: 078, AUC: 0.6509, AP: 0.7088\n",
      "Epoch: 079, AUC: 0.6515, AP: 0.7097\n",
      "Epoch: 080, AUC: 0.6519, AP: 0.7106\n",
      "Epoch: 081, AUC: 0.6522, AP: 0.7115\n",
      "Epoch: 082, AUC: 0.6528, AP: 0.7121\n",
      "Epoch: 083, AUC: 0.6531, AP: 0.7126\n",
      "Epoch: 084, AUC: 0.6540, AP: 0.7136\n",
      "Epoch: 085, AUC: 0.6550, AP: 0.7145\n",
      "Epoch: 086, AUC: 0.6562, AP: 0.7155\n",
      "Epoch: 087, AUC: 0.6571, AP: 0.7163\n",
      "Epoch: 088, AUC: 0.6585, AP: 0.7172\n",
      "Epoch: 089, AUC: 0.6600, AP: 0.7182\n",
      "Epoch: 090, AUC: 0.6624, AP: 0.7195\n",
      "Epoch: 091, AUC: 0.6658, AP: 0.7212\n",
      "Epoch: 092, AUC: 0.6685, AP: 0.7224\n",
      "Epoch: 093, AUC: 0.6707, AP: 0.7234\n",
      "Epoch: 094, AUC: 0.6733, AP: 0.7246\n",
      "Epoch: 095, AUC: 0.6771, AP: 0.7263\n",
      "Epoch: 096, AUC: 0.6812, AP: 0.7283\n",
      "Epoch: 097, AUC: 0.6871, AP: 0.7308\n",
      "Epoch: 098, AUC: 0.6934, AP: 0.7337\n",
      "Epoch: 099, AUC: 0.6985, AP: 0.7361\n",
      "Epoch: 100, AUC: 0.7038, AP: 0.7389\n",
      "Epoch: 101, AUC: 0.7096, AP: 0.7423\n",
      "Epoch: 102, AUC: 0.7147, AP: 0.7451\n",
      "Epoch: 103, AUC: 0.7194, AP: 0.7479\n",
      "Epoch: 104, AUC: 0.7244, AP: 0.7510\n",
      "Epoch: 105, AUC: 0.7281, AP: 0.7533\n",
      "Epoch: 106, AUC: 0.7312, AP: 0.7555\n",
      "Epoch: 107, AUC: 0.7343, AP: 0.7575\n",
      "Epoch: 108, AUC: 0.7369, AP: 0.7591\n",
      "Epoch: 109, AUC: 0.7398, AP: 0.7609\n",
      "Epoch: 110, AUC: 0.7437, AP: 0.7634\n",
      "Epoch: 111, AUC: 0.7462, AP: 0.7649\n",
      "Epoch: 112, AUC: 0.7494, AP: 0.7668\n",
      "Epoch: 113, AUC: 0.7520, AP: 0.7685\n",
      "Epoch: 114, AUC: 0.7547, AP: 0.7703\n",
      "Epoch: 115, AUC: 0.7580, AP: 0.7725\n",
      "Epoch: 116, AUC: 0.7611, AP: 0.7746\n",
      "Epoch: 117, AUC: 0.7633, AP: 0.7759\n",
      "Epoch: 118, AUC: 0.7648, AP: 0.7769\n",
      "Epoch: 119, AUC: 0.7663, AP: 0.7777\n",
      "Epoch: 120, AUC: 0.7676, AP: 0.7783\n",
      "Epoch: 121, AUC: 0.7689, AP: 0.7791\n",
      "Epoch: 122, AUC: 0.7705, AP: 0.7801\n",
      "Epoch: 123, AUC: 0.7721, AP: 0.7814\n",
      "Epoch: 124, AUC: 0.7735, AP: 0.7827\n",
      "Epoch: 125, AUC: 0.7749, AP: 0.7839\n",
      "Epoch: 126, AUC: 0.7756, AP: 0.7844\n",
      "Epoch: 127, AUC: 0.7765, AP: 0.7847\n",
      "Epoch: 128, AUC: 0.7773, AP: 0.7853\n",
      "Epoch: 129, AUC: 0.7783, AP: 0.7862\n",
      "Epoch: 130, AUC: 0.7791, AP: 0.7866\n",
      "Epoch: 131, AUC: 0.7798, AP: 0.7870\n",
      "Epoch: 132, AUC: 0.7808, AP: 0.7877\n",
      "Epoch: 133, AUC: 0.7820, AP: 0.7885\n",
      "Epoch: 134, AUC: 0.7831, AP: 0.7892\n",
      "Epoch: 135, AUC: 0.7839, AP: 0.7899\n",
      "Epoch: 136, AUC: 0.7848, AP: 0.7905\n",
      "Epoch: 137, AUC: 0.7857, AP: 0.7913\n",
      "Epoch: 138, AUC: 0.7865, AP: 0.7920\n",
      "Epoch: 139, AUC: 0.7874, AP: 0.7926\n",
      "Epoch: 140, AUC: 0.7882, AP: 0.7931\n",
      "Epoch: 141, AUC: 0.7885, AP: 0.7934\n",
      "Epoch: 142, AUC: 0.7889, AP: 0.7936\n",
      "Epoch: 143, AUC: 0.7893, AP: 0.7941\n",
      "Epoch: 144, AUC: 0.7898, AP: 0.7945\n",
      "Epoch: 145, AUC: 0.7910, AP: 0.7955\n",
      "Epoch: 146, AUC: 0.7921, AP: 0.7960\n",
      "Epoch: 147, AUC: 0.7929, AP: 0.7963\n",
      "Epoch: 148, AUC: 0.7932, AP: 0.7965\n",
      "Epoch: 149, AUC: 0.7932, AP: 0.7967\n",
      "Epoch: 150, AUC: 0.7930, AP: 0.7969\n",
      "Epoch: 151, AUC: 0.7926, AP: 0.7967\n",
      "Epoch: 152, AUC: 0.7935, AP: 0.7973\n",
      "Epoch: 153, AUC: 0.7940, AP: 0.7976\n",
      "Epoch: 154, AUC: 0.7942, AP: 0.7976\n",
      "Epoch: 155, AUC: 0.7941, AP: 0.7973\n",
      "Epoch: 156, AUC: 0.7941, AP: 0.7976\n",
      "Epoch: 157, AUC: 0.7938, AP: 0.7976\n",
      "Epoch: 158, AUC: 0.7935, AP: 0.7976\n",
      "Epoch: 159, AUC: 0.7934, AP: 0.7976\n",
      "Epoch: 160, AUC: 0.7936, AP: 0.7975\n",
      "Epoch: 161, AUC: 0.7940, AP: 0.7971\n",
      "Epoch: 162, AUC: 0.7944, AP: 0.7971\n",
      "Epoch: 163, AUC: 0.7943, AP: 0.7972\n",
      "Epoch: 164, AUC: 0.7944, AP: 0.7974\n",
      "Epoch: 165, AUC: 0.7942, AP: 0.7975\n",
      "Epoch: 166, AUC: 0.7939, AP: 0.7975\n",
      "Epoch: 167, AUC: 0.7941, AP: 0.7977\n",
      "Epoch: 168, AUC: 0.7946, AP: 0.7978\n",
      "Epoch: 169, AUC: 0.7948, AP: 0.7977\n",
      "Epoch: 170, AUC: 0.7950, AP: 0.7977\n",
      "Epoch: 171, AUC: 0.7947, AP: 0.7980\n",
      "Epoch: 172, AUC: 0.7946, AP: 0.7979\n",
      "Epoch: 173, AUC: 0.7943, AP: 0.7979\n",
      "Epoch: 174, AUC: 0.7943, AP: 0.7979\n",
      "Epoch: 175, AUC: 0.7946, AP: 0.7979\n",
      "Epoch: 176, AUC: 0.7952, AP: 0.7979\n",
      "Epoch: 177, AUC: 0.7955, AP: 0.7978\n",
      "Epoch: 178, AUC: 0.7955, AP: 0.7980\n",
      "Epoch: 179, AUC: 0.7955, AP: 0.7983\n",
      "Epoch: 180, AUC: 0.7949, AP: 0.7985\n",
      "Epoch: 181, AUC: 0.7942, AP: 0.7982\n",
      "Epoch: 182, AUC: 0.7945, AP: 0.7985\n",
      "Epoch: 183, AUC: 0.7954, AP: 0.7987\n",
      "Epoch: 184, AUC: 0.7957, AP: 0.7988\n",
      "Epoch: 185, AUC: 0.7957, AP: 0.7988\n",
      "Epoch: 186, AUC: 0.7954, AP: 0.7987\n",
      "Epoch: 187, AUC: 0.7951, AP: 0.7988\n",
      "Epoch: 188, AUC: 0.7951, AP: 0.7987\n",
      "Epoch: 189, AUC: 0.7953, AP: 0.7988\n",
      "Epoch: 190, AUC: 0.7958, AP: 0.7989\n",
      "Epoch: 191, AUC: 0.7967, AP: 0.7990\n",
      "Epoch: 192, AUC: 0.7966, AP: 0.7989\n",
      "Epoch: 193, AUC: 0.7963, AP: 0.7989\n",
      "Epoch: 194, AUC: 0.7953, AP: 0.7984\n",
      "Epoch: 195, AUC: 0.7952, AP: 0.7984\n",
      "Epoch: 196, AUC: 0.7952, AP: 0.7982\n",
      "Epoch: 197, AUC: 0.7957, AP: 0.7985\n",
      "Epoch: 198, AUC: 0.7957, AP: 0.7984\n",
      "Epoch: 199, AUC: 0.7954, AP: 0.7983\n",
      "Epoch: 200, AUC: 0.7953, AP: 0.7983\n",
      "Epoch: 201, AUC: 0.7952, AP: 0.7983\n",
      "Epoch: 202, AUC: 0.7962, AP: 0.7987\n",
      "Epoch: 203, AUC: 0.7962, AP: 0.7986\n",
      "Epoch: 204, AUC: 0.7957, AP: 0.7985\n",
      "Epoch: 205, AUC: 0.7951, AP: 0.7986\n",
      "Epoch: 206, AUC: 0.7944, AP: 0.7986\n",
      "Epoch: 207, AUC: 0.7942, AP: 0.7985\n",
      "Epoch: 208, AUC: 0.7950, AP: 0.7989\n",
      "Epoch: 209, AUC: 0.7957, AP: 0.7991\n",
      "Epoch: 210, AUC: 0.7964, AP: 0.7990\n",
      "Epoch: 211, AUC: 0.7966, AP: 0.7990\n",
      "Epoch: 212, AUC: 0.7959, AP: 0.7995\n",
      "Epoch: 213, AUC: 0.7944, AP: 0.7989\n",
      "Epoch: 214, AUC: 0.7937, AP: 0.7988\n",
      "Epoch: 215, AUC: 0.7938, AP: 0.7988\n",
      "Epoch: 216, AUC: 0.7946, AP: 0.7991\n",
      "Epoch: 217, AUC: 0.7959, AP: 0.7993\n",
      "Epoch: 218, AUC: 0.7964, AP: 0.7991\n",
      "Epoch: 219, AUC: 0.7966, AP: 0.7991\n",
      "Epoch: 220, AUC: 0.7957, AP: 0.7991\n",
      "Epoch: 221, AUC: 0.7935, AP: 0.7986\n",
      "Epoch: 222, AUC: 0.7923, AP: 0.7981\n",
      "Epoch: 223, AUC: 0.7930, AP: 0.7983\n",
      "Epoch: 224, AUC: 0.7945, AP: 0.7987\n",
      "Epoch: 225, AUC: 0.7955, AP: 0.7987\n",
      "Epoch: 226, AUC: 0.7955, AP: 0.7985\n",
      "Epoch: 227, AUC: 0.7950, AP: 0.7986\n",
      "Epoch: 228, AUC: 0.7939, AP: 0.7985\n",
      "Epoch: 229, AUC: 0.7928, AP: 0.7983\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 230, AUC: 0.7920, AP: 0.7981\n",
      "Epoch: 231, AUC: 0.7926, AP: 0.7983\n",
      "Epoch: 232, AUC: 0.7937, AP: 0.7986\n",
      "Epoch: 233, AUC: 0.7945, AP: 0.7985\n",
      "Epoch: 234, AUC: 0.7944, AP: 0.7984\n",
      "Epoch: 235, AUC: 0.7935, AP: 0.7983\n",
      "Epoch: 236, AUC: 0.7929, AP: 0.7985\n",
      "Epoch: 237, AUC: 0.7921, AP: 0.7980\n",
      "Epoch: 238, AUC: 0.7927, AP: 0.7983\n",
      "Epoch: 239, AUC: 0.7930, AP: 0.7979\n",
      "Epoch: 240, AUC: 0.7929, AP: 0.7978\n",
      "Epoch: 241, AUC: 0.7923, AP: 0.7978\n",
      "Epoch: 242, AUC: 0.7913, AP: 0.7977\n",
      "Epoch: 243, AUC: 0.7910, AP: 0.7975\n",
      "Epoch: 244, AUC: 0.7913, AP: 0.7973\n",
      "Epoch: 245, AUC: 0.7918, AP: 0.7971\n",
      "Epoch: 246, AUC: 0.7922, AP: 0.7971\n",
      "Epoch: 247, AUC: 0.7918, AP: 0.7969\n",
      "Epoch: 248, AUC: 0.7911, AP: 0.7969\n",
      "Epoch: 249, AUC: 0.7902, AP: 0.7965\n",
      "Epoch: 250, AUC: 0.7901, AP: 0.7966\n",
      "Epoch: 251, AUC: 0.7905, AP: 0.7965\n",
      "Epoch: 252, AUC: 0.7913, AP: 0.7966\n",
      "Epoch: 253, AUC: 0.7916, AP: 0.7964\n",
      "Epoch: 254, AUC: 0.7912, AP: 0.7962\n",
      "Epoch: 255, AUC: 0.7904, AP: 0.7961\n",
      "Epoch: 256, AUC: 0.7889, AP: 0.7957\n",
      "Epoch: 257, AUC: 0.7885, AP: 0.7953\n",
      "Epoch: 258, AUC: 0.7883, AP: 0.7952\n",
      "Epoch: 259, AUC: 0.7890, AP: 0.7950\n",
      "Epoch: 260, AUC: 0.7894, AP: 0.7949\n",
      "Epoch: 261, AUC: 0.7896, AP: 0.7948\n",
      "Epoch: 262, AUC: 0.7891, AP: 0.7947\n",
      "Epoch: 263, AUC: 0.7883, AP: 0.7945\n",
      "Epoch: 264, AUC: 0.7870, AP: 0.7944\n",
      "Epoch: 265, AUC: 0.7865, AP: 0.7940\n",
      "Epoch: 266, AUC: 0.7864, AP: 0.7939\n",
      "Epoch: 267, AUC: 0.7867, AP: 0.7938\n",
      "Epoch: 268, AUC: 0.7873, AP: 0.7938\n",
      "Epoch: 269, AUC: 0.7871, AP: 0.7938\n",
      "Epoch: 270, AUC: 0.7868, AP: 0.7938\n",
      "Epoch: 271, AUC: 0.7862, AP: 0.7936\n",
      "Epoch: 272, AUC: 0.7855, AP: 0.7932\n",
      "Epoch: 273, AUC: 0.7855, AP: 0.7932\n",
      "Epoch: 274, AUC: 0.7855, AP: 0.7932\n",
      "Epoch: 275, AUC: 0.7858, AP: 0.7930\n",
      "Epoch: 276, AUC: 0.7860, AP: 0.7930\n",
      "Epoch: 277, AUC: 0.7861, AP: 0.7930\n",
      "Epoch: 278, AUC: 0.7855, AP: 0.7928\n",
      "Epoch: 279, AUC: 0.7849, AP: 0.7927\n",
      "Epoch: 280, AUC: 0.7844, AP: 0.7926\n",
      "Epoch: 281, AUC: 0.7843, AP: 0.7924\n",
      "Epoch: 282, AUC: 0.7847, AP: 0.7925\n",
      "Epoch: 283, AUC: 0.7847, AP: 0.7925\n",
      "Epoch: 284, AUC: 0.7851, AP: 0.7925\n",
      "Epoch: 285, AUC: 0.7851, AP: 0.7925\n",
      "Epoch: 286, AUC: 0.7840, AP: 0.7923\n",
      "Epoch: 287, AUC: 0.7834, AP: 0.7918\n",
      "Epoch: 288, AUC: 0.7829, AP: 0.7915\n",
      "Epoch: 289, AUC: 0.7836, AP: 0.7918\n",
      "Epoch: 290, AUC: 0.7837, AP: 0.7918\n",
      "Epoch: 291, AUC: 0.7836, AP: 0.7914\n",
      "Epoch: 292, AUC: 0.7835, AP: 0.7913\n",
      "Epoch: 293, AUC: 0.7832, AP: 0.7912\n",
      "Epoch: 294, AUC: 0.7825, AP: 0.7907\n",
      "Epoch: 295, AUC: 0.7824, AP: 0.7906\n",
      "Epoch: 296, AUC: 0.7823, AP: 0.7903\n",
      "Epoch: 297, AUC: 0.7816, AP: 0.7900\n",
      "Epoch: 298, AUC: 0.7819, AP: 0.7902\n",
      "Epoch: 299, AUC: 0.7824, AP: 0.7904\n",
      "Epoch: 300, AUC: 0.7824, AP: 0.7904\n"
     ]
    }
   ],
   "source": [
    "writer = SummaryWriter('runs/VGAE_experiment_'+'2d_100_epochs')\n",
    "\n",
    "for epoch in range(1, epochs + 1):\n",
    "    loss = train()\n",
    "    auc, ap = test(data.test_pos_edge_index, data.test_neg_edge_index)\n",
    "    print('Epoch: {:03d}, AUC: {:.4f}, AP: {:.4f}'.format(epoch, auc, ap))\n",
    "    \n",
    "    \n",
    "    writer.add_scalar('auc train',auc,epoch) # new line\n",
    "    writer.add_scalar('ap train',ap,epoch)   # new line"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
